package top.stmo.reflectionTest;


import org.junit.Test;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

/**
 *      获取运行时类的完整结构
 */
public class ReflectionTest5 {
    /**
     *          获取运行时类的属性
     */
    @Test
    public void test1() {
        Class<Student> class1 = Student.class;
        //getFields()：获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = class1.getFields();

        for (Field f : fields) {        //public int top.stmo.reflectionTest.Student.id
            System.out.println(f);      //public double top.stmo.reflectionTest.Person1.weight
        }

        System.out.println("***********************");

        //getDeclaredFields()：获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
        Field[] df = class1.getDeclaredFields();
        for (Field f : df) {        //public int top.stmo.reflectionTest.Student.id
            System.out.println(f);  //int top.stmo.reflectionTest.Student.age
        }                       //private java.lang.String top.stmo.reflectionTest.Student.name
    }

    /**
     *      获取运行时类的属性的内部结构：权限修饰符、数据类型、变量名
     */
    @Test
    public void test2() {
        Field[] df = Student.class.getDeclaredFields();
        for (Field f : df) {
            //权限修饰符
            int modifiers = f.getModifiers();
            System.out.print("权限修饰符为：" + Modifier.toString(modifiers));
            //数据类型
            Class<?> type = f.getType();
            System.out.print(" 数据类型为：" + type);
            //变量名
            String name = f.getName();
            System.out.println(" 变量名为：" + name);
        }
    }

    /**
     *      获取运行时类的方法结构
     */
    @Test
    public void test3() {
        Class<Student> studentClass = Student.class;
        //getMethods()：获取当前运行时类及其父类中声明为public访问权限的方法
        Method[] methods = studentClass.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }

        System.out.println("********************");

        //getDeclaredMethods()：获取当前运行时类中声明的所有方法(不包含父类中声明的方法)
        Method[] dm1 = studentClass.getDeclaredMethods();
        for (Method m : dm1) {
            System.out.println(m);
        }

        System.out.println("********************");

        /**
         *      获取运行时类的方法结构的内部结构
         *
         *      @XXX
         *      权限修饰符   返回值类型   方法名(参数类型1   形参名1,...) throws XxxException()
         */
        Method[] dm2 = studentClass.getDeclaredMethods();
        for (Method m : dm2) {
            //获取方法上声明的注解(能不能获取与注解的生命周期有关)
            Annotation[] annotations = m.getAnnotations();
            for (Annotation a : annotations) {
                System.out.println("注解为：" + a);
            }
            //权限修饰符
            int modifiers = m.getModifiers();
            System.out.println("修饰符为：" + Modifier.toString(modifiers));
            //返回值类型
            Class<?> type = m.getReturnType();
            System.out.println("返回值类型为：" + type);
            //方法名
            System.out.println("方法名为：" + m.getName());
            //形参列表
            Class[] parameterTypes = m.getParameterTypes();
            if (!(parameterTypes == null && parameterTypes.length == 0)) {
                for (Class c : parameterTypes) {
                    System.out.println("形参列表为：" + c);
                }
            }
            //抛出的异常
            Class[] exceptionTypes = m.getExceptionTypes();
            if ((exceptionTypes == null && exceptionTypes.length == 0)) {
                for (Class c : exceptionTypes) {
                    System.out.println("异常类型为：" + c);
                }
            }
        }
    }

    /**
     *    获取运行时类的构造器结构
     */
    @Test
    public void test4() {
        Class<Student> class1 = Student.class;
        //获取当前运行时类中声明为public的构造器
        Constructor[] constructors = class1.getConstructors();
        for (Constructor cs : constructors) {
            System.out.println(cs);
        }

        System.out.println("***************");

        //获取当前运行时类中声明的所有构造器
        Constructor[] declaredConstructors = class1.getDeclaredConstructors();
        for (Constructor dc : declaredConstructors) {
            System.out.println(dc);
        }
    }

    /**
     *      获取运行时类的父类/以及带泛型的父类
     */
    @Test
    public void test5() {
        Class<Student> studentClass = Student.class;

        //取运行时类的父类
        Class superclass = studentClass.getSuperclass();
        System.out.println(superclass);

        System.out.println("*********************");

        //获取运行时类的带泛型的父类
        Type genericSuperclass = studentClass.getGenericSuperclass();
        System.out.println(genericSuperclass);

        System.out.println("*********************");

        //获取运行时类的带泛型的父类的泛型
        Type genericSuperclass1 = studentClass.getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass1;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  //获取泛型参数
        System.out.println(actualTypeArguments[0]);
        System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }

    /**
     *      获取运行时类的接口/及其父类的接口/及其包/及其类上声明的注解
     */
    @Test
    public void test6() {
        Class<Student> studentClass = Student.class;
        //获取运行时类的接口
        Class<?>[] interfaces = studentClass.getInterfaces();
        for (Class cs : interfaces) {
            System.out.println(cs);
        }
        System.out.println("*************");
        //获取运行时类的父类的接口
        Class<?>[] interfaces1 = studentClass.getSuperclass().getInterfaces();
        for (Class cs : interfaces1) {
            System.out.println(cs);
        }
        System.out.println("****************");

        //获取运行时类的父类的包
        Package aPackage = studentClass.getPackage();
        System.out.println(aPackage);

        System.out.println("*****************");

        //获取运行时类其类上声明的注解
        Annotation[] annotations = studentClass.getAnnotations();
        for (Annotation an : annotations) {
            System.out.println(an);
        }

    }
}

class Person1<T> implements Serializable {

    private char gender;

    public double weight;

    private void breath() {
        System.out.println("人呼吸");
    }

    public void eat() {
        System.out.println("人吃东西");
    }
}

@MyAnnotation("hi")
class Student extends Person1<String> implements Comparable<String>,MyInterface {

    private String name;

    int age;

    public int id;

    public Student() {
    }

    private Student(String name) {
        this.name = name;
    }

    @MyAnnotation("aaa")
    Student(String name,int age) {
        this.name = name;
        this.age = age;
    }

    @MyAnnotation
    private String show(String nation) {
        System.out.println("我的国籍是：" + nation);
        return nation;
    }

    public String display(String interest) {
        return interest;
    }

    private static void showDesc() {
        System.out.println("--------showDesc---------");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    @Override
    public void info() {
        System.out.println("我是一个学生");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}

interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String value() default "hello";
}
